home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 April: Mac OS SDK / Dev.CD Apr 98 SDK1.toast / Development Kits (Disc 1) / QuickDraw 3D / Samples / SampleCode / Plug-in - WireFrame Renderer / SR_ClipUtilities.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-14  |  12.9 KB  |  513 lines  |  [TEXT/MPS ]

  1. /******************************************************************************
  2.  **                                                                             **
  3.  **     Module:        SR_ClipUtilities.c                                         **
  4.  **                                                                          **
  5.  **                                                                          **
  6.  **     Purpose:     Clipping utilities for Sample Renderer                     **
  7.  **                                                                          **
  8.  **                                                                          **
  9.  **                                                                          **
  10.  **     Copyright (C) 1996-1997 Apple Computer, Inc.  All rights reserved.     **
  11.  **                                                                          **
  12.  **                                                                          **
  13.  *****************************************************************************/
  14. #include "QD3D.h"
  15. #include "QD3DMath.h"
  16.  
  17. #include "SR.h"
  18. #include "SR_ClipUtilities.h"
  19.  
  20. #define    TRUNC(X)                (float)((long)(X))
  21. #define SUBPIXEL_SNAP            ((float) 64.0)    
  22. #define SUBPIXEL_SNAP_INVERSE    ((float) 1.0 / (float) 64.0)
  23.  
  24.  
  25. /*===========================================================================*\
  26.  *
  27.  *    Routine:    SRPointList_WDivide()
  28.  *
  29.  *    Comments:    
  30.  *
  31. \*===========================================================================*/
  32.  
  33. void SRPointList_WDivide(
  34.     TQ3RationalPoint4D         *in, 
  35.     unsigned long             numVertices, 
  36.     unsigned long             sizeOfIn)
  37. {
  38.     float                    w;
  39.     long                    i;
  40.     TQ3RationalPoint4D        *s = in;
  41.     long                    ci;
  42.     float                    cf;
  43.     float                    c;
  44.     float                    wInv;
  45.  
  46.     for (i = 0; i < numVertices; i++) {
  47.         w = s->w;
  48.         
  49.         if (s->w != 0.0) {
  50.             wInv = 1.0 / w;
  51.         } else {
  52.             wInv = kQ3MaxFloat;
  53.         }
  54.  
  55.         c = s->x * wInv;
  56.         ci = FLOAT_TRUNC_TO_LONG(c);
  57.         cf = c - (float)ci;
  58.         
  59.         cf = FLOAT_ROUND_TO_LONG_POSITIVE(cf * SUBPIXEL_SNAP);
  60.         cf = cf * SUBPIXEL_SNAP_INVERSE;
  61.  
  62.         s->x = (float)ci + cf;
  63.  
  64.         c = s->y * wInv;
  65.         ci = FLOAT_TRUNC_TO_LONG(c);
  66.         cf = c - (float)ci;
  67.         
  68.         cf = FLOAT_ROUND_TO_LONG_POSITIVE(cf * SUBPIXEL_SNAP);
  69.         cf = cf * SUBPIXEL_SNAP_INVERSE;
  70.  
  71.         s->y = (float)ci + cf;
  72.  
  73.         s->z *= wInv;
  74.  
  75.         s = (TQ3RationalPoint4D *)((unsigned char *)s + sizeOfIn);
  76.  
  77.     }
  78. }
  79.  
  80.  
  81. /*===========================================================================*\
  82.  *
  83.  *    Routine:    SRPointList_ClipTestVertices()
  84.  *
  85.  *    Comments:    Check if we have any clipped-out vertices
  86.  *
  87. \*===========================================================================*/
  88.  
  89. void SRPointList_ClipTestVertices(
  90.     TQ3RationalPoint4D         *deviceVertices, 
  91.     unsigned long             *clipFlags, 
  92.     long                     numVertices, 
  93.     float                     *clipPlanes, 
  94.     long                     *clipFound, 
  95.     long                     *allOut, 
  96.     unsigned long             sizeOfIn)
  97. {
  98.     long                i;
  99.     float                x, y, z, w;
  100.     long                clipFlag;
  101.     TQ3RationalPoint4D    *s;
  102.     float                xMin, xMax, 
  103.                         yMin, yMax, 
  104.                         zMin, zMax;
  105.  
  106.     s = deviceVertices;
  107.  
  108.     xMin = clipPlanes[0];
  109.     xMax = clipPlanes[1];
  110.     yMin = clipPlanes[2];
  111.     yMax = clipPlanes[3];
  112.     zMin = clipPlanes[4];
  113.     zMax = clipPlanes[5];
  114.  
  115.     *clipFound = *allOut = 0;
  116.     
  117.     i = 0;
  118.     while (i < numVertices) {
  119.         clipFlag = 0;
  120.  
  121.         x = s->x;
  122.         y = s->y;
  123.         z = s->z;
  124.         w = s->w;
  125.  
  126.         /*
  127.           *  The view clip planes are defined by xmin, xmax, ymin, ymax, 
  128.           *    zmin, zmax. Clearly these planes are perpendicular to the 
  129.           *    appropriate axis.  For example, xmin is perpendicular to the YZ 
  130.           *    plane and defines the minimum x coordinate for clipping.
  131.          *
  132.          *  In this clip test, we allow the clipping planes to be any
  133.          *  value.  They are not just limited to  -1,1 like in some
  134.          *  clipping environments.  The only stipulation is that the
  135.          *  min actually be less than the max for a plane combination.
  136.          *
  137.          *  The same set of tests is applied consistently to all point 
  138.          *    regardless of the sign of w.  Normally, only the geometry in front
  139.          *  of the camera is desired so the tests for the positive- w space 
  140.          *  should be applied consistently.  Sometimes, the geometry in the 
  141.          *  negative w space is desired too.  Then all the points should be 
  142.          *  retraversed with the negative-w tests applied to all points.
  143.          */
  144.         if (x < xMin * w) {
  145.             clipFlag |= SR_MIN_X;
  146.         }
  147.         if (x > xMax * w) {
  148.             clipFlag |= SR_MAX_X;
  149.         }
  150.  
  151.         if (y < yMin * w) {
  152.             clipFlag |= SR_MIN_Y;
  153.         }
  154.         if (y > yMax * w) {
  155.             clipFlag |= SR_MAX_Y;
  156.         }
  157.  
  158.         if (z - w * zMin < 0.0) {
  159.             clipFlag |= SR_MIN_Z;
  160.         } else if (z - w * zMax > 0.0) {
  161.             clipFlag |= SR_MAX_Z;
  162.         }
  163.  
  164.         /* 
  165.          *  All vertices are out if & of all points is not 0 
  166.          */
  167.         if (i == 0) {
  168.             *allOut = clipFlag;
  169.         } else {
  170.             *allOut &= clipFlag;
  171.         }
  172.  
  173.         *clipFound |= clipFlag;
  174.  
  175.         /* 
  176.          *  Vertices are clipped if | of all clip flags is 0 
  177.          */
  178.         clipFlags[i] = clipFlag;
  179.     
  180.         s = (TQ3RationalPoint4D *)((unsigned char *)s + sizeOfIn);
  181.  
  182.         i++;
  183.     }
  184. }
  185.  
  186. #define    OUTPUT_POINT(DEST, SRC_POINT)                            \
  187. {                                                                \
  188.     double    w;                                                    \
  189.                                                                 \
  190.     w = SRC_POINT->w;                                            \
  191.                                                                 \
  192.     DEST->x = (double)SRC_POINT->x / w;                            \
  193.     DEST->y = (double)SRC_POINT->y / w;                            \
  194.     DEST->z = (double)SRC_POINT->z / w;                            \
  195.     DEST->w = 1.0;                                                \
  196. }
  197.  
  198. #define    OUTPUT_POINT_INTERPOLATE(DEST, PREV, CURR, PARAM)        \
  199. {                                                                \
  200.     double    w;                                                    \
  201.     double    oneMinusPARAM;                                        \
  202.                                                                 \
  203.     oneMinusPARAM = (double)1.0 - (double)PARAM;                \
  204.                                                                 \
  205.     w = oneMinusPARAM * (double)PREV->w + (double)PARAM * (double)CURR->w;                \
  206.                                                                                         \
  207.     DEST->x = (oneMinusPARAM * (double)PREV->x + (double)PARAM * (double)CURR->x) / w;    \
  208.     DEST->y = (oneMinusPARAM * (double)PREV->y + (double)PARAM * (double)CURR->y) / w;    \
  209.     DEST->z = (oneMinusPARAM * (double)PREV->z + (double)PARAM * (double)CURR->z) / w;    \
  210.     DEST->w = 1.0;                                                \
  211. }
  212.  
  213. #define COMPUTE_PLANE_INTERSECTIONS(VALUES, COORDS, CLIP_PLANES)            \
  214. {                                                                            \
  215.     int        j;                                                                \
  216.     double    w = COORDS[3];                                                    \
  217.                                                                             \
  218.     for (j = 0; j < 6; j++) {                                                \
  219.           /* For each clip plane; compute parametric intersection. */            \
  220.         VALUES[j] = (double)COORDS[j >> 1] - w * (double)CLIP_PLANES[j];    \
  221.     }                                                                        \
  222. }
  223.  
  224.  
  225. #define    BUMP_DEST_POINTERS                                                    \
  226.     clippedVertices =(TQ3RationalPoint4D *)((unsigned char *)clippedVertices\
  227.         + sizeOfClippedVertex);
  228.  
  229.  
  230.  
  231. /*===========================================================================*\
  232.  *
  233.  *    Routine:    SRPointList_ClipVertices()
  234.  *
  235.  *    Comments:    Given a set of vertices, compute a clipped set.
  236.  *
  237. \*===========================================================================*/
  238.  
  239. void SRPointList_ClipVertices(    
  240.     TQ3RationalPoint4D         *vertices,
  241.     long                     sizeOfVertex,
  242.     TQ3RationalPoint4D         *clippedVertices, 
  243.     long                     sizeOfClippedVertex,
  244.     unsigned long             *clipFlags, 
  245.     long                     *clippedVertexFlags,
  246.     long                     sourceNumberOfPoints, 
  247.     long                     *destNumberOfPoints,
  248.     float                     *clipPlanes,
  249.     long                    mode)
  250. {
  251.     long                    i, j;
  252.     float                    *coords;
  253.     TQ3RationalPoint4D        *sPrevious, 
  254.                             *sCurrent;
  255.     double                    previousValues[6], 
  256.                             currentValues[6];
  257.     double                    prevParametricValue, 
  258.                             currParametricValue;
  259.     double                    parametricValue;
  260.     long                    lineClipped;
  261.     
  262.     (*destNumberOfPoints) = 0;
  263.  
  264.     sPrevious = vertices;
  265.  
  266.     /* if first point not clipped then output it */
  267.     if ((clipFlags[0] & SR_CLIP_ALL) == 0) {
  268.         OUTPUT_POINT(clippedVertices, sPrevious);
  269.         clippedVertexFlags[*destNumberOfPoints] = SR_DRAW_NEXT;
  270.         (*destNumberOfPoints)++;
  271.         BUMP_DEST_POINTERS;
  272.     }
  273.  
  274.     sCurrent = 
  275.         (TQ3RationalPoint4D *)((unsigned char *)sPrevious + sizeOfVertex);
  276.  
  277.     for (i = 1; i < sourceNumberOfPoints; i++) {
  278.         if ((clipFlags[i - 1] & SR_CLIP_ALL) & (clipFlags[i] & SR_CLIP_ALL)) {
  279.             /*  
  280.              *  Previous and current are outside; do nothing 
  281.              */
  282.         } else if (!((clipFlags[i - 1] & SR_CLIP_ALL)     | 
  283.                      (clipFlags[i]     & SR_CLIP_ALL))) {
  284.             /*
  285.              *  Previous and current vertex are inside turn
  286.              *  on draw vector bit and output current vertex
  287.              */
  288.             OUTPUT_POINT(clippedVertices, sCurrent);
  289.             clippedVertexFlags[*destNumberOfPoints] = SR_DRAW_NEXT;
  290.             (*destNumberOfPoints)++;
  291.             BUMP_DEST_POINTERS;
  292.         } else {
  293.             /*
  294.                 * For each clip plane; compute parametric clip with
  295.               * previous and current point.
  296.               */
  297.     
  298.             /* point to current XYZW */
  299.             coords = (float *)&sPrevious->x;
  300.             COMPUTE_PLANE_INTERSECTIONS(previousValues, coords, clipPlanes);
  301.  
  302.             /* point to current XYZW */
  303.             coords = (float *)&sCurrent->x;
  304.             COMPUTE_PLANE_INTERSECTIONS(currentValues, coords, clipPlanes);
  305.  
  306.             prevParametricValue = 0.0;
  307.             currParametricValue = 1.0;
  308.  
  309.             lineClipped = 1;
  310.  
  311.             for (j = 0; j < 6; j++) {
  312.                 /*
  313.                   *  If previous flag and current differ then we cross
  314.                   *  a clip boundary and we must compute the intersection.
  315.                   */
  316.                 if (lineClipped) {
  317.                     if (((clipFlags[i - 1] ^ clipFlags[i]) >> j) & 1) {
  318.  
  319.                         parametricValue = 
  320.                             previousValues[j] / 
  321.                                 (previousValues[j] - currentValues[j]);
  322.  
  323.                         if ((clipFlags[i] >> j) & 1) {
  324.                             if (currParametricValue > parametricValue) {
  325.                                 currParametricValue = parametricValue;
  326.                             }
  327.                         } else {
  328.                             if (prevParametricValue < parametricValue) {
  329.                                 prevParametricValue = parametricValue;
  330.                             }
  331.                         }
  332.                     } else {
  333.                         lineClipped = !((clipFlags[i] >> j) & 1);
  334.                     }
  335.  
  336.                     lineClipped = 
  337.                         lineClipped & 
  338.                             (prevParametricValue < currParametricValue);
  339.                 }
  340.             }
  341.  
  342.             if (lineClipped) {
  343.                 /*
  344.                   *  Compute clip for previous vertex
  345.                   */
  346.                 if (prevParametricValue > 0.0) {
  347.                     OUTPUT_POINT_INTERPOLATE(
  348.                         clippedVertices, 
  349.                         sPrevious, 
  350.                         sCurrent, 
  351.                         prevParametricValue);
  352.                     /*
  353.                      *  Point is clipped on the way into the visible region
  354.                      *  so set draw bit
  355.                      */
  356.                     clippedVertexFlags[*destNumberOfPoints] = SR_DRAW_NEXT;
  357.                     (*destNumberOfPoints)++;
  358.                     BUMP_DEST_POINTERS;
  359.                 }
  360.  
  361.                 /*
  362.                  *  Compute clip for current vertex
  363.                  */
  364.                 if (currParametricValue < 1.0) {
  365.                     OUTPUT_POINT_INTERPOLATE(
  366.                         clippedVertices, 
  367.                         sPrevious, 
  368.                         sCurrent, 
  369.                         currParametricValue);
  370.                     /*
  371.                      *  Point is clipped on the way out of the visible region
  372.                      *  so turn off draw bit
  373.                      */
  374.                     clippedVertexFlags[*destNumberOfPoints] &= ~SR_DRAW_NEXT;
  375.                     (*destNumberOfPoints)++;
  376.                         
  377.                     BUMP_DEST_POINTERS;
  378.                 } else {
  379.                     OUTPUT_POINT(clippedVertices, sCurrent);
  380.  
  381.                     /*
  382.                      *  Point is inside visible region so turn on draw bit
  383.                      */
  384.                     clippedVertexFlags[*destNumberOfPoints] = SR_DRAW_NEXT;
  385.                     (*destNumberOfPoints)++;
  386.                     BUMP_DEST_POINTERS;
  387.                 }
  388.             }
  389.         }
  390.  
  391.         /*
  392.          *  Update previous and current pointers
  393.          */
  394.         sPrevious = sCurrent;
  395.         sCurrent = (TQ3RationalPoint4D *)
  396.                         ((unsigned char *)sPrevious + sizeOfVertex);
  397.     }
  398.  
  399.     /*
  400.      *  If we have fewer than 3 vertices then don't clip from the last to the
  401.      *  first vertex since that doesn't make any sense.
  402.      */
  403.     if (sourceNumberOfPoints < 3) {
  404.         return;
  405.     }
  406.  
  407.     /*
  408.      *  'mode' is either polygon or polyline.  When mode is polygon (0) then 
  409.      *  we must clip from the last vertex to the first vertex.  When mode is 
  410.      *  polyline (1) then we don't do this clip.
  411.      */
  412.     if (mode == DO_POLYLINE) {
  413.         return;
  414.     }
  415.  
  416.     /*
  417.      *  If first vertex is in then do nothing.
  418.      *  If first vertex is clipped and last vertex is displayed then compute
  419.      *    another clip point from last vertex to first
  420.      */
  421.     if (!((clipFlags[0] & SR_CLIP_ALL) | 
  422.         (clipFlags[sourceNumberOfPoints - 1] & SR_CLIP_ALL))) {
  423.         /* 
  424.          *  First and last are inside; do nothing since
  425.          *  draw bit of last should be set
  426.          */
  427.     } else {
  428.         sPrevious = &vertices[sourceNumberOfPoints - 1];
  429.         
  430.         coords = (float *)&sPrevious->x;
  431.         COMPUTE_PLANE_INTERSECTIONS(previousValues, coords, clipPlanes);
  432.  
  433.         sCurrent = vertices;
  434.  
  435.         coords = (float *)&sCurrent->x;
  436.         COMPUTE_PLANE_INTERSECTIONS(currentValues, coords, clipPlanes);
  437.  
  438.         /* compute clip from last vertex to first vertex */
  439.         prevParametricValue = 0.0;
  440.         currParametricValue = 1.0;
  441.  
  442.         lineClipped = 1;
  443.  
  444.         for (j = 0; j < 6; j++) {
  445.             /*
  446.               *  If previous flag and current differ then we cross
  447.               *  a clip boundary and we must compute the intersection.
  448.               */
  449.             if (lineClipped) {
  450.                 if (((clipFlags[sourceNumberOfPoints - 1] ^ clipFlags[0]) >> j) & 1) {
  451.                     parametricValue = previousValues[j] / 
  452.                                         (previousValues[j] - currentValues[j]);
  453.  
  454.                     if ((clipFlags[0] >> j) & 1) {
  455.                         if (currParametricValue > parametricValue) {
  456.                             currParametricValue = parametricValue;
  457.                         }
  458.                     } else {
  459.                         if (prevParametricValue < parametricValue) {
  460.                             prevParametricValue = parametricValue;
  461.                         }
  462.                     }
  463.                 } else {
  464.                     lineClipped = !((clipFlags[0] >> j) & 1);
  465.                 }
  466.  
  467.                 lineClipped = lineClipped & 
  468.                                 (prevParametricValue < currParametricValue);
  469.             }
  470.         }
  471.  
  472.         if (lineClipped) {
  473.             /*
  474.               *  Compute clip for previous vertex
  475.               */
  476.             if (prevParametricValue > 0.0) {
  477.                 OUTPUT_POINT_INTERPOLATE(
  478.                     clippedVertices, 
  479.                     sPrevious, 
  480.                     sCurrent, 
  481.                     prevParametricValue);
  482.                 clippedVertexFlags[*destNumberOfPoints] = SR_DRAW_NEXT;
  483.                 (*destNumberOfPoints)++;
  484.                 BUMP_DEST_POINTERS;
  485.             }
  486.  
  487.             /*
  488.              *  Compute clip for current vertex
  489.              */
  490.             if (currParametricValue < 1.0) {
  491.                 OUTPUT_POINT_INTERPOLATE(
  492.                     clippedVertices, 
  493.                     sPrevious, 
  494.                     sCurrent, 
  495.                     currParametricValue);
  496.                 clippedVertexFlags[*destNumberOfPoints] &= ~SR_DRAW_NEXT;
  497.                 (*destNumberOfPoints)++;
  498.                 BUMP_DEST_POINTERS;
  499.             } else {
  500.                 OUTPUT_POINT(clippedVertices, sCurrent);
  501.  
  502.                 /*
  503.                  *  Point is clipped so compute last vertex and don't 
  504.                  *  display it
  505.                  */
  506.                 clippedVertexFlags[*destNumberOfPoints] = SR_DRAW_NEXT;
  507.                 (*destNumberOfPoints)++;
  508.                 BUMP_DEST_POINTERS;
  509.             }
  510.         }
  511.     }
  512. }
  513.